package l1j.opqlo.Server;

import static l1j.server.server.model.skill.L1SkillId.CANCELLATION;
import static l1j.server.server.model.skill.L1SkillId.SHAPE_CHANGE;

import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.NewSystem.各項記錄輸出;
import l1j.opqlo.Server.L1World.L1World;
import l1j.server.Config;
import l1j.server.server.ActionCodes;
import l1j.server.server.model.L1Character;
import l1j.server.server.model.L1Quest;
import l1j.server.server.model.L1Trade;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.model.skill.L1SkillUse;
import l1j.server.server.serverpackets.S_BlueMessage;
import l1j.server.server.serverpackets.S_ChangeShape;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_GreenMessage;
import l1j.server.server.serverpackets.S_Lawful;
import l1j.server.server.serverpackets.S_PacketBox;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.utils.Random;

public class PcDeath implements Runnable {
	private static final Logger _log = Logger.getLogger(PcDeath.class.getName());

	private final static String[] message = { "割下GG餵豬", "打個稀巴爛", "童子拜觀音",
		"挑斷手腳筋", "五馬分屍", "開刀割盲腸", "砍了108刀", "說了冷笑話", "全壘打轟頭", "晃了幾下",
		"什麼都沒做", "替他割痔瘡" };

	final L1Character _lastAttacker;
	final L1PcInstance _pc;

	public PcDeath(final L1PcInstance pc, final L1Character cha) {
		this._lastAttacker = cha;
		this._pc = pc;
	}

	private void caoPenaltyResult(int count) {
		try{

			final Timestamp time = new Timestamp(System.currentTimeMillis());
			final String name = this._pc.getName();
			final String st1 = "】 流水號: ";
			final String st0 = "\r\n";
			boolean log = false;
			final StringBuilder st = new StringBuilder(256).append("IP").append("(")
					.append(this._pc.getNetConnection().getIp().toString())
					.append(") 玩家:【").append(name).append("】 在 【")
					.append(this._pc.getMapId()).append("】 噴裝").append(" 時間:")
					.append(time).append(st0).append("【");

			final List<L1ItemInstance> items = this._pc.getInventory().CaoPenalty();
			count = Math.min(count, items.size());
			L1ItemInstance ProtectionItem = null;
			for (int i = 0; i < count; i++) {

				final int LoseCount = Random.nextInt(items.size());
				final L1ItemInstance item = items.get(LoseCount);

				if (item != null) {
					items.remove(LoseCount);
					this._pc.getInventory().setEquipped(item, false);// 脫下裝備

					final int itemid = item.getId();
					ProtectionItem = this._pc.getInventory().findItemId(780013);
					if(ProtectionItem == null){
						ProtectionItem = this._pc.getInventory().findItemId(780066);
					}

					if (ProtectionItem != null) {
						this._pc.getInventory().removeItem(ProtectionItem, 1);
						this._pc.sendPackets(new S_SystemMessage("\\f2 "
								+ "防噴發揮作用，阻止 " + item.getName() + " 噴出!"));// opqlo
						// 封印防噴

						continue;
					} else {
						this._pc.sendPackets(new S_SystemMessage("你損失了「 "+ item.getLogName() + " 」"));

						// TODO 防止噴裝洗裝備
						if (Config.Dead_Lost_Item) {
							// final int itemCount = item.getCount(); // TODO
							// 死亡處罰
							this._pc.getInventory().removeItem(item);// TODO
							// 死亡處罰
						} else {
							this._pc.getInventory().tradeItem(
									item,item.isStackable() ? item.getCount() : 1,L1World.getInstance().getInventory(
											this._pc.getX(), this._pc.getY(),this._pc.getMapId()));

							// final String itemname = item.getLogName();
							// TODO 使用物品記錄by opqlo*/
							st.append(item.getViewName()).append(st1)
							.append(itemid).append(st0);

							// TODO 使用物品記錄by opqlo*/
							// BroadCastToAll("【"+name+"】噴了【"+itemname+"】！");
						}
						if (log != true) {
							log = true;
						}
					}
				}
			}
			if (log) {
				各項記錄輸出.LogSave(10, st.toString());
				st.delete(0, st.length());
			}
		}catch(Exception e){
			_log.log(Level.SEVERE, e.getLocalizedMessage() , e);
		}
	}

	@Override
	public void run() {
		try {

			this._pc.setCurrentHp(0);
			_pc.addMaxHp(-_pc.getExtraHp());
			_pc.addMaxMp(-_pc.getExtraMp());
			_pc.setExtraHp(0);
			_pc.setExtraMp(0);
			this._pc.setGresValid(false); // EXPロストするまでG-RES無効

			while (this._pc.isTeleport()) { // テレポート中なら終わるまで待つ
				try {
					Thread.sleep(300);
				} catch (final InterruptedException e) {
					e.printStackTrace();
				}

			}

			this._pc.stopHpRegeneration();
			this._pc.stopMpRegeneration();

			final int targetobjid = this._pc.getId();
			this._pc.getMap().setPassable(this._pc.getLocation(), true);

			// エンチャントを解除する
			// 変身状態も解除されるため、キャンセレーションをかけてから変身状態に戻す
			int tempchargfx = 0;
			if (this._pc.hasSkillEffect(SHAPE_CHANGE)) {
				tempchargfx = this._pc.getTempCharGfx();
				this._pc.setTempCharGfxAtDead(tempchargfx);
			} else {
				this._pc.setTempCharGfxAtDead(this._pc.getClassId());
			}
			// TODO 修正角色人物不在螢幕內可進行交易的BUG
			if (this._pc.getTradeID() != 0) {// TODO 交易中
				final L1Trade trade = new L1Trade();
				trade.TradeCancel(this._pc);
			}
			// TODO 修正角色人物不在螢幕內可進行交易的BUG
			// キャンセレーションをエフェクトなしでかける
			new L1SkillUse().handleCommands(this._pc, CANCELLATION,
					this._pc.getId(), this._pc.getX(), this._pc.getY(),
					null, 0, L1SkillUse.TYPE_LOGIN);

			// シャドウ系変身中に死亡するとクライアントが落ちるため暫定対応
			if (tempchargfx == 5727 || tempchargfx == 5730
					|| tempchargfx == 5733 || tempchargfx == 5736) {
				tempchargfx = 0;
			}
			if (tempchargfx != 0) {
				this._pc.sendPacketsAll(new S_ChangeShape(this._pc.getId(),
						tempchargfx));
			} else {
				// シャドウ系変身中に攻撃しながら死亡するとクライアントが落ちるためディレイを入れる
				try {
					Thread.sleep(1000);
				} catch (final InterruptedException e) {
					e.printStackTrace();
				}
			}
			this._pc.sendPacketsAll(new S_DoActionGFX(targetobjid,
					ActionCodes.ACTION_Die));

			if (this._lastAttacker != this._pc) {
				// セーフティーゾーン、コンバットゾーンで最後に殺したキャラが
				// プレイヤーorペットだったら、ペナルティなし
				if (this._pc.getZoneType() != 0) {
					L1PcInstance player = null;
					if (this._lastAttacker instanceof L1PcInstance) {
						player = (L1PcInstance) this._lastAttacker;
					} else if (this._lastAttacker instanceof L1PetInstance) {
						player = (L1PcInstance) ((L1PetInstance) this._lastAttacker)
								.getMaster();
					} else if (this._lastAttacker instanceof L1SummonInstance) {
						player = (L1PcInstance) ((L1SummonInstance) this._lastAttacker)
								.getMaster();
					}
					if (player != null) {
						// 戦争中に戦争エリアに居る場合は例外
						if (!this._pc.isInWarAreaAndWarTime(this._pc,player)) {
							return;
						}
					}
				}

				final boolean sim_ret = this._pc
						.simWarResult(this._lastAttacker); // 模擬戦
				if (sim_ret == true) { // 模擬戦中ならペナルティなし
					return;
				}
			}

			if (!this._pc.getMap().isEnabledDeathPenalty()) {
				return;
			}

			// 決闘中ならペナルティなし
			L1PcInstance fightPc = null;
			if (this._lastAttacker instanceof L1PcInstance) {
				fightPc = (L1PcInstance) this._lastAttacker;
			}

			// TODO 判斷是否屬於新手保護階段, 並且是被其他玩家所殺死
			// boolean isNovice = false;
			// if (_pc.hasSkillEffect(L1SkillId.STATUS_NOVICE) && (fightPc
			// != null)) {

			// TODO 判斷是否在新手等級保護範圍內
			// if (fightPc.getLevel() > (_pc.getLevel() +
			// Config.NOVICE_PROTECTION_LEVEL_RANGE)) {
			// isNovice = true;
			// }
			// }
			if (fightPc != null) {
				if (this._pc.getFightId() == fightPc.getId()
						&& fightPc.getFightId() == this._pc.getId()) { // 決闘中
					this._pc.setFightId(0);
					final S_PacketBox box = new S_PacketBox(
							S_PacketBox.MSG_DUEL, 0, 0);
					this._pc.sendPackets(box);
					fightPc.setFightId(0);
					fightPc.sendPackets(box);
					return;
				}
			}

			this._pc.deathPenalty(); // EXPロスト

			this._pc.setGresValid(true); // EXPロストしたらG-RES有効

			if (this._pc.getExpRes() == 0) {
				this._pc.setExpRes(1);
			}

			boolean isPVP = false;

			// ガードに殺された場合のみ、PKカウントを減らしガードに攻撃されなくなる
			//			if (this._lastAttacker instanceof L1GuardInstance) {
			//				if (this._pc.get_PKcount() > 0) {
			//					this._pc.set_PKcount(this._pc.get_PKcount() - 1);
			//				}
			//				this._pc.setLastPk(null);
			//
			//			} else if (this._lastAttacker instanceof L1GuardianInstance) {
			//				if (this._pc.getPkCountForElf() > 0) {
			//					this._pc.setPkCountForElf(this._pc.getPkCountForElf() - 1);
			//				}
			//				this._pc.setLastPkForElf(null);
			//			} else
			if (this._lastAttacker instanceof L1PcInstance) {
				isPVP = true;
			}
			/** 噴裝相關判定 */
			// 一定の確率でアイテムをDROP
			// アライメント32000以上で0%、以降-1000毎に0.4%
			// アライメントが0未満の場合は-1000毎に0.8%
			// アライメント-32000以下で最高51.2%のDROP率
			if (!this._pc.isGm() && !this._pc.isMonitor()) {
				if (isPVP&& this._pc.getQuest().get_step(L1Quest.QUEST_opqlo新手保護) == 1) {
					this._pc.sendPackets(new S_SystemMessage("\\aD處於新手保護階段，遭PVP死亡不噴裝。"));
				} else if (!isPVP && this._pc.get_metempsychosis() <= 30) {
					this._pc.sendPackets(new S_SystemMessage("\\aD30轉以下(包含30轉)，遭怪物殺死不噴裝。"));
				} else {
					final int getLawful = this._pc.getLawful();
					if (getLawful <= -30000) {
						this.caoPenaltyResult(Random.nextInt(8) + 1);
					} else if (getLawful <= -20000) {
						this.caoPenaltyResult(Random.nextInt(4) + 1);
					} else if (getLawful <= -10000) {
						this.caoPenaltyResult(Random.nextInt(2) + 1);
					} else if (getLawful < 0) {
						this.caoPenaltyResult(1);
					} else {
						int lostRate = (int) (((getLawful + 32768D) / 1000D - 65D) * 4D);
						if (lostRate < 0) {
							lostRate *= -1;
							final int rnd = Random.nextInt(1000) + 1;
							if (rnd <= lostRate) {
								this.caoPenaltyResult(1);
							}
						}
					}
				}
			}
			final boolean castle_ret = this._pc.castleWarResult(); // 攻城戦
			if (castle_ret == true) { // 攻城戦中で旗内なら赤ネームペナルティなし
				return;
			}

			// 最後に殺したキャラがプレイヤーだったら、赤ネームにする
			L1PcInstance attacker = null;
			if (this._lastAttacker instanceof L1PcInstance) {
				attacker = (L1PcInstance) this._lastAttacker;
			}
			if (attacker != null) {
				boolean isAddHell = false;
				if (this._pc.getLawful() >= 0
						&& this._pc.isPinkName() == false) {

					final int PKcount = attacker.get_PKcount()+1;
					attacker.add_PKcount();
					//					boolean isChangePkCount = false;
					// boolean isChangePkCountForElf = false;
					// アライメントが30000未満の場合はPKカウント増加
					//					if (player.getLawful() < 30000) {
					//						player.set_PKcount(player.get_PKcount() + 1);
					//						isChangePkCount = true;
					//						if (player.isElf() && this._pc.isElf()) {
					//							player.setPkCountForElf(player.getPkCountForElf() + 1);
					//							// isChangePkCountForElf = true;
					//						}
					//					}
					if (attacker.isElf() && this._pc.isElf()) {
						attacker.setLastPkForElf();
					}
					attacker.setLastPk();
					final int attackid = attacker.getId();
					L1World.getInstance().putKillerId(_pc.getId(), attackid);
					_pc.setLastKillerId(attackid);
					final L1Quest quest = attacker.getQuest();
					if (quest.get_step(L1Quest.QUEST_opqlo新手保護) == 1) {
						quest.set_end(L1Quest.QUEST_opqlo新手保護);
						attacker.sendPackets(new S_SystemMessage("\\aD你主動PVP了玩家，失去新手保護的效果。"));
					}
					if(PKcount >=250){
						isAddHell = true;
					}
					// アライメント処理
					// 公式の発表および各LVでのPKからつじつまの合うように変更
					// （PK側のLVに依存し、高LVほどリスクも高い）
					// 48あたりで-8kほど DKの時点で10k強
					// 60で約20k強 65で30k弱
					int lawful;

					if (attacker.getLevel() < 50) {
						lawful = -1* (int) (Math.pow(attacker.getLevel(), 2) * 4);
					} else {
						lawful = -1* (int) (Math.pow(attacker.getLevel(), 3) * 0.08);
					}
					// もし(元々のアライメント-1000)が計算後より低い場合
					// 元々のアライメント-1000をアライメント値とする
					// （連続でPKしたときにほとんど値が変わらなかった記憶より）
					// これは上の式よりも自信度が低いうろ覚えですので
					// 明らかにこうならない！という場合は修正お願いします
					if (attacker.getLawful() - 1000 < lawful) {
						lawful = attacker.getLawful() - 1000;
					}
					lawful = Math.max(lawful, -32768);
					attacker.setLawful(lawful);

					attacker.sendPacketsAll(new S_Lawful(attackid,attacker.getLawful()));
					//					final int PKcount = player.get_PKcount();
					//					if (isChangePkCount && PKcount >= 5 && PKcount < 10) {
					//						// あなたのPK回数が%0になりました。回数が%1になると地獄行きです。
					//						player.sendPackets(new S_BlueMessage(551, String.valueOf(PKcount), "10"));
					//					} else if (isChangePkCount && PKcount >= 1000) {
					//						player.beginHell(true);
					//					}
				} else {
					this._pc.setPinkName(false);
				}

				try {
					final String msg = message[Random .nextInt(message.length)];
					final String ss = new StringBuilder()
					.append("\\f2" + "[ ")
					.append(this._pc.getName()).append(" ] 慘遭 [ ")
					.append(attacker.getName()).append(" ]拿【  ")
					.append(attacker.getWeapon().getLogName())
					.append(" 】").append(msg).append("後，他就死了")
					.toString();
					final Collection<L1PcInstance> AllPc = L1World.getInstance().getAllPlayers();
					for (final L1PcInstance pc : AllPc) {
						if (pc != null) {
							if(pc ==this._pc || pc == attacker || pc.getConfig().isPVPIfo()){
								if(pc == attacker && isAddHell){
									attacker.sendPackets(new S_BlueMessage(551, String.valueOf(attacker.get_PKcount()), "300"));
								}else{
									pc.sendPackets(new S_GreenMessage(ss));
//									pc.sendPackets(new S_BlueMessage(166, ss));
								}
							}
						}
					}
				} catch (final Exception e) {
					_log.log(Level.SEVERE, e.getLocalizedMessage() , e);
				}
			}
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage() , e);
		}
		this._pc.set_delete_time(180);
		// _pcDeleteTimer = new L1PcDeleteTimer(getNetConnection());
		// _pcDeleteTimer.begin();
	}
}
